﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

namespace ModularAndPlugin.ESB.WCFPlugin.Extensibility
{
    public class ExtensibilityManager
    {
        #region Members
        static ExtensibilityManager instance = null;
        private CompositionContainer Container { get; set; } 

        //[ImportMany(typeof(IService))]
        //public IService[] ProductServiceExtensions { get; set; }

        #endregion

        #region Constructors
        private ExtensibilityManager()
        {
            Compose();
        }
        #endregion

        #region Properties
        public static ExtensibilityManager Instance
        {
            get
            {
                if (instance == null)
                    instance = new ExtensibilityManager();

                return instance;
            }
        }
        #endregion

        #region Public Methods

        public void InvokeExtension(Type contractType, string operationName,object[] arguments)
        {
            ImportDefinition importDefinition = new ImportDefinition(i => i.ContractName.Equals(contractType.FullName), contractType.FullName, ImportCardinality.ZeroOrMore, false, false);
            AtomicComposition atomicComposition = new AtomicComposition();
            IEnumerable<Export> extensions = null;

            bool exportDiscovery = this.Container.TryGetExports(importDefinition, atomicComposition, out extensions);
            
            if (extensions != null && extensions.Count<Export>() > 0)
            {
                foreach (Export extensionExport in extensions)
                {
                    contractType.InvokeMember(operationName, System.Reflection.BindingFlags.InvokeMethod, null, extensionExport.Value, arguments);
                }
            }
        }

        #endregion

        #region Private Methods

        private void Compose()
        {
            var Catalog = new AggregateCatalog();
            Catalog.Catalogs.Add(new DirectoryCatalog(@".\Extensions"));
            this.Container = new CompositionContainer(Catalog);
            this.Container.ComposeParts(this);            
        }

        #endregion
    }
}